Having an in-between bytecode layer allows you to build application architectures in rust that would not be possible when compiling directly to machine code. Hot reloading is a good example. Having the VM hold onto resources like tcp streams and file descriptors allows you to exchange the business logic without even breaking a tcp connection. Fine-grained sandboxing is another good example. Revoking filesystem access from just parts of your applications or limiting memory/cpu usage for each individual request[1] is something that is just impossible to do correctly without a vm managing it.
A less obvious benefit are the improvements to the developer experience, like compile times. Most of the dependencies (async executor, tcp stack, message passing, ...) are usually already part of the wasm runtime and don't need to be compiled/linked again. The rust compiler also seems to have a better time when it comes to generating .wasm executables instead of native ones. Most rust wasm apps I write compile much faster than equivalent native ones. Just because there is so much less for the compiler to do.
Many wasm runtimes, like lunatic, include an async scheduler and green threads/processes. This means that you get most of the benefits of async rust without needing to actually use async and worry about all the issues that come with it[2].
[0]: https://github.com/lunatic-solutions/lunatic
[1]: https://www.youtube.com/watch?v=8gwSU3oaMV8&list=PLdo4fOcmZ0...