diff --git a/Cargo.toml b/Cargo.toml
index 2627de0..1c190ca 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,6 +29,7 @@ tracing = { version = "0.1", default-features = false, features = ["std"], optio
 tokio = { version = "1", optional = true, default-features = false  }
 tower-service ={ version = "0.3", optional = true }
 tower = { version = "0.4.1", optional = true, default-features = false, features = ["make", "util"] }
+sync_wrapper = { version = "1", optional = true }
 
 [dev-dependencies]
 hyper = { version = "1.2.0", features = ["full"] }
@@ -57,7 +58,7 @@ full = [
 ]
 
 client = ["hyper/client", "dep:tracing", "dep:futures-channel", "dep:tower", "dep:tower-service"]
-client-legacy = ["client", "dep:socket2", "tokio/sync"]
+client-legacy = ["client", "dep:socket2", "dep:sync_wrapper", "tokio/sync"]
 
 server = ["hyper/server"]
 server-auto = ["server", "http1", "http2"]
diff --git a/src/client/legacy/client.rs b/src/client/legacy/client.rs
index 166c572..ce91710 100644
--- a/src/client/legacy/client.rs
+++ b/src/client/legacy/client.rs
@@ -16,6 +16,7 @@ use http::uri::Scheme;
 use hyper::header::{HeaderValue, HOST};
 use hyper::rt::Timer;
 use hyper::{body::Body, Method, Request, Response, Uri, Version};
+use sync_wrapper::SyncWrapper;
 use tracing::{debug, trace, warn};
 
 use super::connect::capture::CaptureConnectionExtension;
@@ -24,7 +25,7 @@ use super::connect::HttpConnector;
 use super::connect::{Alpn, Connect, Connected, Connection};
 use super::pool::{self, Ver};
 
-use crate::common::{lazy as hyper_lazy, timer, Exec, Lazy, SyncWrapper};
+use crate::common::{lazy as hyper_lazy, timer, Exec, Lazy};
 
 type BoxSendFuture = Pin<Box<dyn Future<Output = ()> + Send>>;
 
diff --git a/src/common/mod.rs b/src/common/mod.rs
index 63b8288..f599640 100644
--- a/src/common/mod.rs
+++ b/src/common/mod.rs
@@ -4,8 +4,6 @@ pub(crate) mod exec;
 #[cfg(feature = "client")]
 mod lazy;
 pub(crate) mod rewind;
-#[cfg(feature = "client")]
-mod sync;
 pub(crate) mod timer;
 
 #[cfg(feature = "client")]
@@ -13,5 +11,3 @@ pub(crate) use exec::Exec;
 
 #[cfg(feature = "client")]
 pub(crate) use lazy::{lazy, Started as Lazy};
-#[cfg(feature = "client")]
-pub(crate) use sync::SyncWrapper;
diff --git a/src/common/sync.rs b/src/common/sync.rs
deleted file mode 100644
index 2755fd0..0000000
--- a/src/common/sync.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-pub(crate) struct SyncWrapper<T>(T);
-
-impl<T> SyncWrapper<T> {
-    /// Creates a new SyncWrapper containing the given value.
-    ///
-    /// # Examples
-    ///
-    /// ```ignore
-    /// use hyper::common::sync_wrapper::SyncWrapper;
-    ///
-    /// let wrapped = SyncWrapper::new(42);
-    /// ```
-    pub(crate) fn new(value: T) -> Self {
-        Self(value)
-    }
-
-    /// Acquires a reference to the protected value.
-    ///
-    /// This is safe because it requires an exclusive reference to the wrapper. Therefore this method
-    /// neither panics nor does it return an error. This is in contrast to [`Mutex::get_mut`] which
-    /// returns an error if another thread panicked while holding the lock. It is not recommended
-    /// to send an exclusive reference to a potentially damaged value to another thread for further
-    /// processing.
-    ///
-    /// [`Mutex::get_mut`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html#method.get_mut
-    ///
-    /// # Examples
-    ///
-    /// ```ignore
-    /// use hyper::common::sync_wrapper::SyncWrapper;
-    ///
-    /// let mut wrapped = SyncWrapper::new(42);
-    /// let value = wrapped.get_mut();
-    /// *value = 0;
-    /// assert_eq!(*wrapped.get_mut(), 0);
-    /// ```
-    pub(crate) fn get_mut(&mut self) -> &mut T {
-        &mut self.0
-    }
-
-    /// Consumes this wrapper, returning the underlying data.
-    ///
-    /// This is safe because it requires ownership of the wrapper, aherefore this method will neither
-    /// panic nor does it return an error. This is in contrast to [`Mutex::into_inner`] which
-    /// returns an error if another thread panicked while holding the lock. It is not recommended
-    /// to send an exclusive reference to a potentially damaged value to another thread for further
-    /// processing.
-    ///
-    /// [`Mutex::into_inner`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html#method.into_inner
-    ///
-    /// # Examples
-    ///
-    /// ```ignore
-    /// use hyper::common::sync_wrapper::SyncWrapper;
-    ///
-    /// let mut wrapped = SyncWrapper::new(42);
-    /// assert_eq!(wrapped.into_inner(), 42);
-    /// ```
-    #[allow(dead_code)]
-    pub(crate) fn into_inner(self) -> T {
-        self.0
-    }
-}
-
-// this is safe because the only operations permitted on this data structure require exclusive
-// access or ownership
-unsafe impl<T: Send> Sync for SyncWrapper<T> {}