diff --git a/cumulus/Cargo.lock b/cumulus/Cargo.lock
index d249158bfcc46fde1296c412ec80b4b1bdb231bd..f2c36dfacdef5828107a21a003ff28ec53dfb69a 100644
--- a/cumulus/Cargo.lock
+++ b/cumulus/Cargo.lock
@@ -1304,6 +1304,7 @@ dependencies = [
  "parity-scale-codec",
  "sp-std",
  "xcm",
+ "xcm-executor",
 ]
 
 [[package]]
diff --git a/cumulus/pallets/xcm-handler/Cargo.toml b/cumulus/pallets/xcm-handler/Cargo.toml
index b982c1dba69d0b02b140c70edf43c7309d13a8d9..c5d57a2b329b4282718eb1ab68c39aa27d52afd7 100644
--- a/cumulus/pallets/xcm-handler/Cargo.toml
+++ b/cumulus/pallets/xcm-handler/Cargo.toml
@@ -16,6 +16,7 @@ frame-system = { git = "https://github.com/paritytech/substrate", default-featur
 
 # Polkadot Dependencies
 xcm = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
+xcm-executor = { git = "https://github.com/paritytech/polkadot", default-features = false, branch = "master" }
 
 # Cumulus Dependencies
 cumulus-primitives-core = { path = "../../primitives/core", default-features = false }
@@ -29,5 +30,6 @@ std = [
 	"frame-support/std",
 	"frame-system/std",
 	"cumulus-primitives-core/std",
-	"xcm/std"
+	"xcm/std",
+	"xcm-executor/std",
 ]
diff --git a/cumulus/pallets/xcm-handler/src/lib.rs b/cumulus/pallets/xcm-handler/src/lib.rs
index 1f80eee78075ed0d8b347a29726d0a416f2b1634..03d50fa19ac8fe30d601393a96ed3b202d455d42 100644
--- a/cumulus/pallets/xcm-handler/src/lib.rs
+++ b/cumulus/pallets/xcm-handler/src/lib.rs
@@ -27,12 +27,13 @@ use cumulus_primitives_core::{
 	DownwardMessageHandler, HrmpMessageHandler, HrmpMessageSender, InboundDownwardMessage,
 	InboundHrmpMessage, OutboundHrmpMessage, ParaId, UpwardMessageSender,
 };
-use frame_support::{decl_error, decl_event, decl_module, sp_runtime::traits::Hash, traits::EnsureOrigin};
+use frame_support::{decl_error, decl_event, decl_module, dispatch::DispatchResult, sp_runtime::traits::Hash, traits::EnsureOrigin};
 use sp_std::convert::{TryFrom, TryInto};
 use xcm::{
 	v0::{Error as XcmError, ExecuteXcm, Junction, MultiLocation, SendXcm, Xcm},
 	VersionedXcm,
 };
+use xcm_executor::traits::LocationConversion;
 
 pub trait Config: frame_system::Config {
 	type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;
@@ -45,6 +46,9 @@ pub trait Config: frame_system::Config {
 	/// Required origin for sending XCM messages. Typically Root or parachain
 	/// council majority.
 	type SendXcmOrigin: EnsureOrigin<Self::Origin>;
+	/// Utility for converting from the signed origin (of type `Self::AccountId`) into a sensible
+	/// `MultiLocation` ready for passing to the XCM interpreter.
+	type AccountIdConverter: LocationConversion<Self::AccountId>;
 }
 
 decl_event! {
@@ -68,6 +72,8 @@ decl_error! {
 	pub enum Error for Module<T: Config> {
 		/// Failed to send XCM message.
 		FailedToSend,
+		/// Bad XCM origin.
+		BadXcmOrigin,
 	}
 }
 
@@ -101,6 +107,21 @@ decl_module! {
 	}
 }
 
+impl<T: Config> Module<T> {
+	/// Execute an XCM message locally. Returns `DispatchError` if failed.
+	pub fn execute_xcm(origin: T::AccountId, xcm: Xcm) -> DispatchResult {
+		let xcm_origin = T::AccountIdConverter::try_into_location(origin)
+			.map_err(|_| Error::<T>::BadXcmOrigin)?;
+		let hash = T::Hashing::hash(&xcm.encode());
+		let event = match T::XcmExecutor::execute_xcm(xcm_origin, xcm) {
+			Ok(_) => Event::<T>::Success(hash),
+			Err(e) => Event::<T>::Fail(hash, e),
+		};
+		Self::deposit_event(event);
+		Ok(())
+	}
+}
+
 impl<T: Config> DownwardMessageHandler for Module<T> {
 	fn handle_downward_message(msg: InboundDownwardMessage) {
 		let hash = msg.using_encoded(T::Hashing::hash);
diff --git a/cumulus/rococo-parachains/runtime/src/lib.rs b/cumulus/rococo-parachains/runtime/src/lib.rs
index 3c1741a6210841ec8aaef49b71116451d0fcce12..b056057149cc4808e7b29454c1fba07d814282f5 100644
--- a/cumulus/rococo-parachains/runtime/src/lib.rs
+++ b/cumulus/rococo-parachains/runtime/src/lib.rs
@@ -290,6 +290,7 @@ impl cumulus_pallet_xcm_handler::Config for Runtime {
 	type UpwardMessageSender = ParachainSystem;
 	type HrmpMessageSender = ParachainSystem;
 	type SendXcmOrigin = EnsureRoot<AccountId>;
+	type AccountIdConverter = LocationConverter;
 }
 
 construct_runtime! {