diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs
index 03bd5b18b5bed..bbb010f60bffe 100644
--- a/polkadot/runtime/westend/src/lib.rs
+++ b/polkadot/runtime/westend/src/lib.rs
@@ -61,12 +61,16 @@ use runtime_common::{
 	impls::{
 		LocatableAssetConverter, ToAuthor, VersionedLocatableAsset, VersionedLocationConverter,
 	},
-	paras_registrar, paras_sudo_wrapper, prod_or_fast, slots, BalanceToU256, BlockHashCount,
-	BlockLength, CurrencyToVote, SlowAdjustingFeeUpdate, U256ToBalance,
+	paras_registrar, paras_sudo_wrapper, prod_or_fast, slots,
+	traits::Leaser,
+	BalanceToU256, BlockHashCount, BlockLength, CurrencyToVote, SlowAdjustingFeeUpdate,
+	U256ToBalance,
 };
 use runtime_parachains::{
+	assigner_coretime as parachains_assigner_coretime,
+	assigner_on_demand as parachains_assigner_on_demand,
 	assigner_parachains as parachains_assigner_parachains,
-	configuration as parachains_configuration, disputes as parachains_disputes,
+	configuration as parachains_configuration, coretime, disputes as parachains_disputes,
 	disputes::slashing as parachains_slashing,
 	dmp as parachains_dmp, hrmp as parachains_hrmp, inclusion as parachains_inclusion,
 	inclusion::{AggregateMessageOrigin, UmpQueueId},
@@ -147,7 +151,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
 	spec_name: create_runtime_str!("westend"),
 	impl_name: create_runtime_str!("parity-westend"),
 	authoring_version: 2,
-	spec_version: 1_007_000,
+	spec_version: 1_007_001,
 	impl_version: 0,
 	apis: RUNTIME_API_VERSIONS,
 	transaction_version: 24,
@@ -1143,7 +1147,7 @@ impl parachains_paras::Config for Runtime {
 	type QueueFootprinter = ParaInclusion;
 	type NextSessionRotation = Babe;
 	type OnNewHead = ();
-	type AssignCoretime = ();
+	type AssignCoretime = CoretimeAssignmentProvider;
 }
 
 parameter_types! {
@@ -1212,20 +1216,42 @@ impl parachains_paras_inherent::Config for Runtime {
 impl parachains_scheduler::Config for Runtime {
 	// If you change this, make sure the `Assignment` type of the new provider is binary compatible,
 	// otherwise provide a migration.
-	type AssignmentProvider = ParachainsAssignmentProvider;
+	type AssignmentProvider = CoretimeAssignmentProvider;
 }
 
 parameter_types! {
 	pub const BrokerId: u32 = BROKER_ID;
 }
 
+impl coretime::Config for Runtime {
+	type RuntimeOrigin = RuntimeOrigin;
+	type RuntimeEvent = RuntimeEvent;
+	type Currency = Balances;
+	type BrokerId = BrokerId;
+	type WeightInfo = weights::runtime_parachains_coretime::WeightInfo<Runtime>;
+	type SendXcm = crate::xcm_config::XcmRouter;
+}
+
+parameter_types! {
+	pub const OnDemandTrafficDefaultValue: FixedU128 = FixedU128::from_u32(1);
+}
+
+impl parachains_assigner_on_demand::Config for Runtime {
+	type RuntimeEvent = RuntimeEvent;
+	type Currency = Balances;
+	type TrafficDefaultValue = OnDemandTrafficDefaultValue;
+	type WeightInfo = weights::runtime_parachains_assigner_on_demand::WeightInfo<Runtime>;
+}
+
 impl parachains_assigner_parachains::Config for Runtime {}
 
+impl parachains_assigner_coretime::Config for Runtime {}
+
 impl parachains_initializer::Config for Runtime {
 	type Randomness = pallet_babe::RandomnessFromOneEpochAgo<Runtime>;
 	type ForceOrigin = EnsureRoot<AccountId>;
 	type WeightInfo = weights::runtime_parachains_initializer::WeightInfo<Runtime>;
-	type CoretimeOnNewSession = ();
+	type CoretimeOnNewSession = Coretime;
 }
 
 impl paras_sudo_wrapper::Config for Runtime {}
@@ -1480,6 +1506,8 @@ construct_runtime! {
 		ParasDisputes: parachains_disputes = 53,
 		ParasSlashing: parachains_slashing = 54,
 		ParachainsAssignmentProvider: parachains_assigner_parachains = 55,
+		OnDemandAssignmentProvider: parachains_assigner_on_demand = 56,
+		CoretimeAssignmentProvider: parachains_assigner_coretime = 57,
 
 		// Parachain Onboarding Pallets. Start indices at 60 to leave room.
 		Registrar: paras_registrar = 60,
@@ -1488,6 +1516,7 @@ construct_runtime! {
 		Auctions: auctions = 63,
 		Crowdloan: crowdloan = 64,
 		AssignedSlots: assigned_slots = 65,
+		Coretime: coretime = 66,
 
 		// Pallet for sending XCM.
 		XcmPallet: pallet_xcm = 99,
@@ -1555,6 +1584,24 @@ pub mod migrations {
 	#[cfg(feature = "try-runtime")]
 	use sp_core::crypto::ByteArray;
 
+	pub struct GetLegacyLeaseImpl;
+	impl coretime::migration::GetLegacyLease<BlockNumber> for GetLegacyLeaseImpl {
+		fn get_parachain_lease_in_blocks(para: ParaId) -> Option<BlockNumber> {
+			let now = frame_system::Pallet::<Runtime>::block_number();
+			let lease = slots::Pallet::<Runtime>::lease(para);
+			if lease.is_empty() {
+				return None
+			}
+			// Lease not yet started, ignore:
+			if lease.iter().any(Option::is_none) {
+				return None
+			}
+			let (index, _) =
+				<slots::Pallet<Runtime> as Leaser<BlockNumber>>::lease_period_index(now)?;
+			Some(index.saturating_add(lease.len() as u32).saturating_mul(LeasePeriod::get()))
+		}
+	}
+
 	parameter_types! {
 		pub const ImOnlinePalletName: &'static str = "ImOnline";
 	}
@@ -1658,6 +1705,12 @@ pub mod migrations {
 		parachains_configuration::migration::v11::MigrateToV11<Runtime>,
 		// permanent
 		pallet_xcm::migration::MigrateToLatestXcmVersion<Runtime>,
+		// Migrate from legacy lease to coretime. Needs to run after configuration v11
+		coretime::migration::MigrateToCoretime<
+			Runtime,
+			crate::xcm_config::XcmRouter,
+			GetLegacyLeaseImpl,
+		>,
 	);
 }
 
@@ -1696,6 +1749,8 @@ mod benches {
 		[runtime_parachains::initializer, Initializer]
 		[runtime_parachains::paras, Paras]
 		[runtime_parachains::paras_inherent, ParaInherent]
+		[runtime_parachains::assigner_on_demand, OnDemandAssignmentProvider]
+		[runtime_parachains::coretime, Coretime]
 		// Substrate
 		[pallet_bags_list, VoterList]
 		[pallet_balances, Balances]
diff --git a/polkadot/runtime/westend/src/weights/runtime_parachains_coretime.rs b/polkadot/runtime/westend/src/weights/runtime_parachains_coretime.rs
index d9f2d45207b92..aa65a2e9034a7 100644
--- a/polkadot/runtime/westend/src/weights/runtime_parachains_coretime.rs
+++ b/polkadot/runtime/westend/src/weights/runtime_parachains_coretime.rs
@@ -16,11 +16,11 @@
 
 //! Autogenerated weights for `runtime_parachains::coretime`
 //!
-//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
-//! DATE: 2023-12-01, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
+//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0
+//! DATE: 2024-02-15, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
 //! WORST CASE MAP SIZE: `1000000`
-//! HOSTNAME: `runner-r43aesjn-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
-//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("rococo-dev")`, DB CACHE: 1024
+//! HOSTNAME: `runner-bn-ce5rx-project-674-concurrent-0`, CPU: `Intel(R) Xeon(R) CPU @ 2.60GHz`
+//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("westend-dev")`, DB CACHE: 1024
 
 // Executed Command:
 // target/production/polkadot
@@ -32,10 +32,10 @@
 // --wasm-execution=compiled
 // --heap-pages=4096
 // --json-file=/builds/parity/mirrors/polkadot-sdk/.git/.artifacts/bench.json
-// --pallet=runtime_common::coretime
-// --chain=rococo-dev
+// --pallet=runtime_parachains::coretime
+// --chain=westend-dev
 // --header=./polkadot/file_header.txt
-// --output=./polkadot/runtime/rococo/src/weights/
+// --output=./polkadot/runtime/westend/src/weights/
 
 #![cfg_attr(rustfmt, rustfmt_skip)]
 #![allow(unused_parens)]
@@ -45,28 +45,39 @@
 use frame_support::{traits::Get, weights::Weight};
 use core::marker::PhantomData;
 
-use runtime_parachains::configuration::{self, WeightInfo as ConfigWeightInfo};
-
-/// Weight functions for `runtime_common::coretime`.
+/// Weight functions for `runtime_parachains::coretime`.
 pub struct WeightInfo<T>(PhantomData<T>);
-impl<T: frame_system::Config + configuration::Config> runtime_parachains::coretime::WeightInfo for WeightInfo<T> {
+impl<T: frame_system::Config> runtime_parachains::coretime::WeightInfo for WeightInfo<T> {
+	/// Storage: `Configuration::PendingConfigs` (r:1 w:1)
+	/// Proof: `Configuration::PendingConfigs` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `Configuration::BypassConsistencyCheck` (r:1 w:0)
+	/// Proof: `Configuration::BypassConsistencyCheck` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
+	/// Storage: `ParasShared::CurrentSessionIndex` (r:1 w:0)
+	/// Proof: `ParasShared::CurrentSessionIndex` (`max_values`: Some(1), `max_size`: None, mode: `Measured`)
 	fn request_core_count() -> Weight {
-		<T as configuration::Config>::WeightInfo::set_config_with_u32()
+		// Proof Size summary in bytes:
+		//  Measured:  `151`
+		//  Estimated: `1636`
+		// Minimum execution time: 7_486_000 picoseconds.
+		Weight::from_parts(7_889_000, 0)
+			.saturating_add(Weight::from_parts(0, 1636))
+			.saturating_add(T::DbWeight::get().reads(3))
+			.saturating_add(T::DbWeight::get().writes(1))
 	}
-	/// Storage: `CoreTimeAssignmentProvider::CoreDescriptors` (r:1 w:1)
-	/// Proof: `CoreTimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`)
-	/// Storage: `CoreTimeAssignmentProvider::CoreSchedules` (r:0 w:1)
-	/// Proof: `CoreTimeAssignmentProvider::CoreSchedules` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `CoretimeAssignmentProvider::CoreDescriptors` (r:1 w:1)
+	/// Proof: `CoretimeAssignmentProvider::CoreDescriptors` (`max_values`: None, `max_size`: None, mode: `Measured`)
+	/// Storage: `CoretimeAssignmentProvider::CoreSchedules` (r:0 w:1)
+	/// Proof: `CoretimeAssignmentProvider::CoreSchedules` (`max_values`: None, `max_size`: None, mode: `Measured`)
 	/// The range of component `s` is `[1, 100]`.
 	fn assign_core(s: u32, ) -> Weight {
 		// Proof Size summary in bytes:
-		//  Measured:  `76`
-		//  Estimated: `3541`
-		// Minimum execution time: 6_275_000 picoseconds.
-		Weight::from_parts(6_883_543, 0)
-			.saturating_add(Weight::from_parts(0, 3541))
-			// Standard Error: 202
-			.saturating_add(Weight::from_parts(15_028, 0).saturating_mul(s.into()))
+		//  Measured:  `147`
+		//  Estimated: `3612`
+		// Minimum execution time: 9_409_000 picoseconds.
+		Weight::from_parts(10_177_115, 0)
+			.saturating_add(Weight::from_parts(0, 3612))
+			// Standard Error: 259
+			.saturating_add(Weight::from_parts(13_932, 0).saturating_mul(s.into()))
 			.saturating_add(T::DbWeight::get().reads(1))
 			.saturating_add(T::DbWeight::get().writes(2))
 	}
diff --git a/polkadot/runtime/westend/src/xcm_config.rs b/polkadot/runtime/westend/src/xcm_config.rs
index a11c52156c830..06124d896fbb3 100644
--- a/polkadot/runtime/westend/src/xcm_config.rs
+++ b/polkadot/runtime/westend/src/xcm_config.rs
@@ -115,11 +115,13 @@ parameter_types! {
 	pub Collectives: Location = Parachain(COLLECTIVES_ID).into_location();
 	pub BridgeHub: Location = Parachain(BRIDGE_HUB_ID).into_location();
 	pub People: Location = Parachain(PEOPLE_ID).into_location();
+	pub Broker: Location = Parachain(BROKER_ID).into_location();
 	pub Wnd: AssetFilter = Wild(AllOf { fun: WildFungible, id: AssetId(TokenLocation::get()) });
 	pub WndForAssetHub: (AssetFilter, Location) = (Wnd::get(), AssetHub::get());
 	pub WndForCollectives: (AssetFilter, Location) = (Wnd::get(), Collectives::get());
 	pub WndForBridgeHub: (AssetFilter, Location) = (Wnd::get(), BridgeHub::get());
 	pub WndForPeople: (AssetFilter, Location) = (Wnd::get(), People::get());
+	pub WndForBroker: (AssetFilter, Location) = (Wnd::get(), Broker::get());
 	pub MaxInstructions: u32 = 100;
 	pub MaxAssetsIntoHolding: u32 = 64;
 }
@@ -129,6 +131,7 @@ pub type TrustedTeleporters = (
 	xcm_builder::Case<WndForCollectives>,
 	xcm_builder::Case<WndForBridgeHub>,
 	xcm_builder::Case<WndForPeople>,
+	xcm_builder::Case<WndForBroker>,
 );
 
 pub struct OnlyParachains;
diff --git a/polkadot/xcm/src/v2/mod.rs b/polkadot/xcm/src/v2/mod.rs
index 188b7f0b5c938..347f3f2c29206 100644
--- a/polkadot/xcm/src/v2/mod.rs
+++ b/polkadot/xcm/src/v2/mod.rs
@@ -1134,7 +1134,10 @@ impl<RuntimeCall> TryFrom<NewInstruction<RuntimeCall>> for Instruction<RuntimeCa
 				max_response_weight: max_response_weight.ref_time(),
 			},
 			UnsubscribeVersion => Self::UnsubscribeVersion,
-			_ => return Err(()),
+			i => {
+				log::debug!(target: "xcm::v3tov2", "`{i:?}` not supported by v2");
+				return Err(());
+			},
 		})
 	}
 }
diff --git a/prdoc/pr_3319.prdoc b/prdoc/pr_3319.prdoc
new file mode 100644
index 0000000000000..b84ec25a22eda
--- /dev/null
+++ b/prdoc/pr_3319.prdoc
@@ -0,0 +1,11 @@
+# Schema: Polkadot SDK PRDoc Schema (prdoc) v1.0.0
+# See doc at https://raw.githubusercontent.com/paritytech/polkadot-sdk/master/prdoc/schema_user.json
+
+title: Add Coretime to Westend
+
+doc:
+  - audience: Runtime User
+    description: |
+      Add the on demand and coretime assigners and migrate from legacy parachain auctions to coretime.
+
+crates: [ ]