diff --git a/axum/CHANGELOG.md b/axum/CHANGELOG.md
index 06b3f37b..96f783d1 100644
--- a/axum/CHANGELOG.md
+++ b/axum/CHANGELOG.md
@@ -363,6 +363,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 - **fixed:** Annotate panicking functions with `#[track_caller]` so the error
   message points to where the user added the invalid route, rather than
   somewhere internally in axum ([#1248])
+- **added:** Add `ServiceExt` with methods for turning any `Service` into a
+  `MakeService` similarly to `Router::into_make_service` ([#1302])
 
 [#1077]: https://github.com/tokio-rs/axum/pull/1077
 [#1086]: https://github.com/tokio-rs/axum/pull/1086
@@ -375,6 +377,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 [#1248]: https://github.com/tokio-rs/axum/pull/1248
 [#1272]: https://github.com/tokio-rs/axum/pull/1272
 [#1301]: https://github.com/tokio-rs/axum/pull/1301
+[#1302]: https://github.com/tokio-rs/axum/pull/1302
 [#924]: https://github.com/tokio-rs/axum/pull/924
 
 # 0.5.15 (9. August, 2022)
diff --git a/axum/src/docs/middleware.md b/axum/src/docs/middleware.md
index 8d0e970c..1830bbd6 100644
--- a/axum/src/docs/middleware.md
+++ b/axum/src/docs/middleware.md
@@ -8,6 +8,7 @@
 - [Routing to services/middleware and backpressure](#routing-to-servicesmiddleware-and-backpressure)
 - [Accessing state in middleware](#accessing-state-in-middleware)
 - [Passing state from middleware to handlers](#passing-state-from-middleware-to-handlers)
+- [Rewriting request URI in middleware](#rewriting-request-uri-in-middleware)
 
 # Intro
 
@@ -557,6 +558,47 @@ let app = Router::new()
 automatically moved to response extensions. You need to manually do that for the
 extensions you need.
 
+# Rewriting request URI in middleware
+
+Middleware added with [`Router::layer`] will run after routing. That means it
+cannot be used to run middleware that rewrites the request URI. By the time the
+middleware runs the routing is already done.
+
+The workaround is to wrap the middleware around the entire `Router` (this works
+because `Router` implements [`Service`]):
+
+```rust
+use tower::Layer;
+use axum::{
+    Router,
+    ServiceExt, // for `into_make_service`
+    response::Response,
+    middleware::Next,
+    http::Request,
+};
+
+async fn rewrite_request_uri<B>(req: Request<B>, next: Next<B>) -> Response {
+    // ...
+    # next.run(req).await
+}
+
+// this can be any `tower::Layer`
+let middleware = axum::middleware::from_fn(rewrite_request_uri);
+
+let app = Router::new();
+
+// apply the layer around the whole `Router`
+// this way the middleware will run before `Router` receives the request
+let app_with_middleware = middleware.layer(app);
+
+# async {
+axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
+    .serve(app_with_middleware.into_make_service())
+    .await
+    .unwrap();
+# };
+```
+
 [`tower`]: https://crates.io/crates/tower
 [`tower-http`]: https://crates.io/crates/tower-http
 [tower-guides]: https://github.com/tower-rs/tower/tree/master/guides
@@ -576,3 +618,4 @@ extensions you need.
 [request extensions]: https://docs.rs/http/latest/http/request/struct.Request.html#method.extensions
 [Response extensions]: https://docs.rs/http/latest/http/response/struct.Response.html#method.extensions
 [`State`]: crate::extract::State
+[`Service`]: tower::Service
diff --git a/axum/src/docs/routing/layer.md b/axum/src/docs/routing/layer.md
index f659babb..0f835e41 100644
--- a/axum/src/docs/routing/layer.md
+++ b/axum/src/docs/routing/layer.md
@@ -9,6 +9,11 @@ of routes.
 Note this differs from [`Handler::layer`](crate::handler::Handler::layer)
 which adds a middleware to a single handler.
 
+Middleware added with this method will run _after_ routing and thus cannot be
+used to rewrite the request URI. See ["Rewriting request URI in
+middleware"](crate::middleware#rewriting-request-uri-in-middleware) for more
+details and a workaround.
+
 # Example
 
 Adding the [`tower::limit::ConcurrencyLimit`] middleware to a group of
diff --git a/axum/src/ext_traits/mod.rs b/axum/src/ext_traits/mod.rs
index 131e99b1..ca039f6c 100644
--- a/axum/src/ext_traits/mod.rs
+++ b/axum/src/ext_traits/mod.rs
@@ -1,5 +1,6 @@
 pub(crate) mod request;
 pub(crate) mod request_parts;
+pub(crate) mod service;
 
 #[cfg(test)]
 mod tests {
diff --git a/axum/src/ext_traits/service.rs b/axum/src/ext_traits/service.rs
new file mode 100644
index 00000000..b901a34b
--- /dev/null
+++ b/axum/src/ext_traits/service.rs
@@ -0,0 +1,43 @@
+use crate::{extract::connect_info::IntoMakeServiceWithConnectInfo, routing::IntoMakeService};
+use tower_service::Service;
+
+/// Extension trait that adds additional methods to any [`Service`].
+pub trait ServiceExt<R>: Service<R> + Sized {
+    /// Convert this service into a [`MakeService`], that is a [`Service`] whose
+    /// response is another service.
+    ///
+    /// This is commonly used when applying middleware around an entire [`Router`]. See ["Rewriting
+    /// request URI in middleware"] for more details.
+    ///
+    /// [`MakeService`]: tower::make::MakeService
+    /// ["Rewriting request URI in middleware"]: crate::middleware#rewriting-request-uri-in-middleware
+    /// [`Router`]: crate::Router
+    fn into_make_service(self) -> IntoMakeService<Self>;
+
+    /// Convert this service into a [`MakeService`], that will store `C`'s
+    /// associated `ConnectInfo` in a request extension such that [`ConnectInfo`]
+    /// can extract it.
+    ///
+    /// This enables extracting things like the client's remote address.
+    /// This is commonly used when applying middleware around an entire [`Router`]. See ["Rewriting
+    /// request URI in middleware"] for more details.
+    ///
+    /// [`MakeService`]: tower::make::MakeService
+    /// ["Rewriting request URI in middleware"]: crate::middleware#rewriting-request-uri-in-middleware
+    /// [`Router`]: crate::Router
+    /// [`ConnectInfo`]: crate::extract::connect_info::ConnectInfo
+    fn into_make_service_with_connect_info<C>(self) -> IntoMakeServiceWithConnectInfo<Self, C>;
+}
+
+impl<S, R> ServiceExt<R> for S
+where
+    S: Service<R> + Sized,
+{
+    fn into_make_service(self) -> IntoMakeService<Self> {
+        IntoMakeService::new(self)
+    }
+
+    fn into_make_service_with_connect_info<C>(self) -> IntoMakeServiceWithConnectInfo<Self, C> {
+        IntoMakeServiceWithConnectInfo::new(self)
+    }
+}
diff --git a/axum/src/lib.rs b/axum/src/lib.rs
index c74e80bb..f3edba26 100644
--- a/axum/src/lib.rs
+++ b/axum/src/lib.rs
@@ -486,4 +486,6 @@ pub use axum_core::{BoxError, Error};
 #[cfg(feature = "macros")]
 pub use axum_macros::debug_handler;
 
-pub use self::ext_traits::{request::RequestExt, request_parts::RequestPartsExt};
+pub use self::ext_traits::{
+    request::RequestExt, request_parts::RequestPartsExt, service::ServiceExt,
+};