In particular, it is a real pain having to pass mutable references when a non-reference value would do, and Read and Write are blanket-impl'd for reference types anyway. So yeah, just use the first one.
Note that functions with the first signature cannot be called recursively and repeatedly.
convert_stream_as::<R, W, T>(reader, writer) -> io::Result<()> cannot call convert_stream_as(reader, writer) itself more than once inside it, since the first recursive call moves ownership of the reader and writer to the callee.
Calling convert_stream_as<_, _, T>(&mut reader, &mut writer) also does not compile because it depends on more deeply nested convert_stream_as() infinitely.
convert_stream_as::<R, W, T> depends on convert_stream_as::<&mut R, &mut W, T>(), and it depends on convert_stream_as::<&mut &mut R, &mut &mut W, T>(), and so on.
On the other hand, reader: &mut R, writer: &mut W version allows recursive call (example on playground).
This might be problem if you want to define, for example, serializer and deserializer for complex nested types such as tree structure.
If this restriction won't affect your use case (for now and in future), prefer reader: R, writer: W version.
Okay, I noticed that you can make recursively called functions receive reader: R, writer: W, by making it proxy to the reader: &mut R, writer: &mut W version.
You can always use reader: R, writer: W. Prefer it for public API.
This would cause extra dereference when R and W is a reference to some other reader / writer types, but I don't know how much it costs and how well the compiler optimizes them.