It turns out that my initial code was basically correct; the only change required was to change
request.ContentLength = clientRequest.InputStream.Length;
to
request.ContentLength = clientRequest.ContentLength;
The former streams in the entire request to determine the content length; the latter merely checks the Content-Length
header, which only requires that the headers have been sent in full. This allows IIS to begin streaming the request almost immediately, which completely eliminates the original problem.