With Windows 3.1, you're probably talking about having to compile to the Win16 interface, which would be a bit of a challenge.
LLVM's x86 backend doesn't really support 16-bit compilation (the best it gets to is supporting 32-bit in a 16-bit code segment). There's also no support for the Win16-based object file formats. So you'd probably be best off creating your own entirely new backend for a Win16 environment... which probably is easier than you'd think, given that you could ignore anything more complicated than the actual Intel 386 or 486 ISA. (I've actually started sketching out what the IR for such a backend would look like, mostly in terms of LLVM address space mappings).
Win16 is also kind of hard to target for Rust because it's a segmented memory model, and Rust's pointer model doesn't really cope with that well--it only supports one pointer type, and also requires that sizeof(ptr) == sizeof(usize) which is questionable for far pointers. If you're writing your own backend, you could just map everything to huge pointers at the programmer level and have optimization passes that convert them down to far or near pointers if sufficient.
Or you could stuff all of that, and just make a 32-bit app and wrap it in a shell loader that thunks all of the OS calls to 16-bit calls and vice-versa.
Maybe it could be half way there with Win32s.
likely no_std, and running via Win32s. Rust doesn't have support for segmented memory, so native 16-bit would be much harder
I believe there is AVR support for Rust, which is 16-bit with separate code and data pointer types?