diff --git a/polkadot/runtime/rococo/src/governance/mod.rs b/polkadot/runtime/rococo/src/governance/mod.rs
index 2be549be29ed14a80c3856cc0db2fa359c83cbcc..4052dfcdd0bec1aff309db08446bfe5acb765df0 100644
--- a/polkadot/runtime/rococo/src/governance/mod.rs
+++ b/polkadot/runtime/rococo/src/governance/mod.rs
@@ -47,6 +47,7 @@ impl pallet_conviction_voting::Config for Runtime {
 	type MaxTurnout =
 		frame_support::traits::tokens::currency::ActiveIssuanceOf<Balances, Self::AccountId>;
 	type Polls = Referenda;
+	type BlockNumberProvider = System;
 }
 
 parameter_types! {
diff --git a/polkadot/runtime/westend/src/governance/mod.rs b/polkadot/runtime/westend/src/governance/mod.rs
index abc25ebaa470833a9bd188b5747ac641638a2fcc..aa4294f033b049a926a8537d0add3766c474197c 100644
--- a/polkadot/runtime/westend/src/governance/mod.rs
+++ b/polkadot/runtime/westend/src/governance/mod.rs
@@ -44,6 +44,7 @@ impl pallet_conviction_voting::Config for Runtime {
 	type MaxTurnout =
 		frame_support::traits::tokens::currency::ActiveIssuanceOf<Balances, Self::AccountId>;
 	type Polls = Referenda;
+	type BlockNumberProvider = System;
 }
 
 parameter_types! {
diff --git a/prdoc/pr_6621.prdoc b/prdoc/pr_6621.prdoc
new file mode 100644
index 0000000000000000000000000000000000000000..c7d9792957eef62a6ab5bbfd5fd685745f4f4ad1
--- /dev/null
+++ b/prdoc/pr_6621.prdoc
@@ -0,0 +1,14 @@
+# 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: Update Conviction Voting Pallet to Support Block Number Provider
+
+doc:
+  - audience: Runtime Dev
+    description: |
+      This PR makes the block number provider used in the society pallet configurable. Before this PR, society pallet always used the system block number,
+      with this PR some runtime can opt to use the relay chain block number instead.
+
+crates:
+- name: pallet-conviction-voting
+  bump: major
\ No newline at end of file
diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index db5392d943c001e4e93162ddb131834635eb8eb7..4e04dc22468768a3e3430eb14e40d223bebc95ca 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -1004,6 +1004,7 @@ impl pallet_conviction_voting::Config for Runtime {
 	type MaxVotes = ConstU32<512>;
 	type MaxTurnout = frame_support::traits::TotalIssuanceOf<Balances, Self::AccountId>;
 	type Polls = Referenda;
+	type BlockNumberProvider = System;
 }
 
 parameter_types! {
diff --git a/substrate/frame/conviction-voting/src/lib.rs b/substrate/frame/conviction-voting/src/lib.rs
index 31bd6b85ec866303b82e978c939d414cc11999bc..3dd2ad24298d344d4122933546406fd3dc8c9fb9 100644
--- a/substrate/frame/conviction-voting/src/lib.rs
+++ b/substrate/frame/conviction-voting/src/lib.rs
@@ -37,7 +37,6 @@ use frame_support::{
 		ReservableCurrency, WithdrawReasons,
 	},
 };
-use frame_system::pallet_prelude::BlockNumberFor;
 use sp_runtime::{
 	traits::{AtLeast32BitUnsigned, Saturating, StaticLookup, Zero},
 	ArithmeticError, DispatchError, Perbill,
@@ -55,6 +54,7 @@ pub use self::{
 	vote::{AccountVote, Casting, Delegating, Vote, Voting},
 	weights::WeightInfo,
 };
+use sp_runtime::traits::BlockNumberProvider;
 
 #[cfg(test)]
 mod tests;
@@ -64,19 +64,22 @@ pub mod benchmarking;
 
 const CONVICTION_VOTING_ID: LockIdentifier = *b"pyconvot";
 
+pub type BlockNumberFor<T, I> =
+	<<T as Config<I>>::BlockNumberProvider as BlockNumberProvider>::BlockNumber;
+
 type AccountIdLookupOf<T> = <<T as frame_system::Config>::Lookup as StaticLookup>::Source;
 type BalanceOf<T, I = ()> =
 	<<T as Config<I>>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
 type VotingOf<T, I = ()> = Voting<
 	BalanceOf<T, I>,
 	<T as frame_system::Config>::AccountId,
-	BlockNumberFor<T>,
+	BlockNumberFor<T, I>,
 	PollIndexOf<T, I>,
 	<T as Config<I>>::MaxVotes,
 >;
 #[allow(dead_code)]
 type DelegatingOf<T, I = ()> =
-	Delegating<BalanceOf<T, I>, <T as frame_system::Config>::AccountId, BlockNumberFor<T>>;
+	Delegating<BalanceOf<T, I>, <T as frame_system::Config>::AccountId, BlockNumberFor<T, I>>;
 pub type TallyOf<T, I = ()> = Tally<BalanceOf<T, I>, <T as Config<I>>::MaxTurnout>;
 pub type VotesOf<T, I = ()> = BalanceOf<T, I>;
 type PollIndexOf<T, I = ()> = <<T as Config<I>>::Polls as Polling<TallyOf<T, I>>>::Index;
@@ -94,7 +97,7 @@ pub mod pallet {
 		traits::ClassCountOf,
 		Twox64Concat,
 	};
-	use frame_system::pallet_prelude::*;
+	use frame_system::pallet_prelude::{ensure_signed, OriginFor};
 	use sp_runtime::BoundedVec;
 
 	#[pallet::pallet]
@@ -109,14 +112,14 @@ pub mod pallet {
 		type WeightInfo: WeightInfo;
 		/// Currency type with which voting happens.
 		type Currency: ReservableCurrency<Self::AccountId>
-			+ LockableCurrency<Self::AccountId, Moment = BlockNumberFor<Self>>
+			+ LockableCurrency<Self::AccountId, Moment = BlockNumberFor<Self, I>>
 			+ fungible::Inspect<Self::AccountId>;
 
 		/// The implementation of the logic which conducts polls.
 		type Polls: Polling<
 			TallyOf<Self, I>,
 			Votes = BalanceOf<Self, I>,
-			Moment = BlockNumberFor<Self>,
+			Moment = BlockNumberFor<Self, I>,
 		>;
 
 		/// The maximum amount of tokens which may be used for voting. May just be
@@ -136,7 +139,9 @@ pub mod pallet {
 		/// It should be no shorter than enactment period to ensure that in the case of an approval,
 		/// those successful voters are locked into the consequences that their votes entail.
 		#[pallet::constant]
-		type VoteLockingPeriod: Get<BlockNumberFor<Self>>;
+		type VoteLockingPeriod: Get<BlockNumberFor<Self, I>>;
+		/// Provider for the block number. Normally this is the `frame_system` pallet.
+		type BlockNumberProvider: BlockNumberProvider;
 	}
 
 	/// All voting for a particular voter in a particular voting class. We store the balance for the
@@ -479,7 +484,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 							let unlock_at = end.saturating_add(
 								T::VoteLockingPeriod::get().saturating_mul(lock_periods.into()),
 							);
-							let now = frame_system::Pallet::<T>::block_number();
+							let now = T::BlockNumberProvider::current_block_number();
 							if now < unlock_at {
 								ensure!(
 									matches!(scope, UnvoteScope::Any),
@@ -620,7 +625,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 							&class,
 							conviction.votes(balance),
 						);
-						let now = frame_system::Pallet::<T>::block_number();
+						let now = T::BlockNumberProvider::current_block_number();
 						let lock_periods = conviction.lock_periods().into();
 						prior.accumulate(
 							now.saturating_add(
@@ -666,7 +671,7 @@ impl<T: Config<I>, I: 'static> Pallet<T, I> {
 	/// a security hole) but may be reduced from what they are currently.
 	fn update_lock(class: &ClassOf<T, I>, who: &T::AccountId) {
 		let class_lock_needed = VotingFor::<T, I>::mutate(who, class, |voting| {
-			voting.rejig(frame_system::Pallet::<T>::block_number());
+			voting.rejig(T::BlockNumberProvider::current_block_number());
 			voting.locked_balance()
 		});
 		let lock_needed = ClassLocksFor::<T, I>::mutate(who, |locks| {
diff --git a/substrate/frame/conviction-voting/src/tests.rs b/substrate/frame/conviction-voting/src/tests.rs
index b1b1fab5ae50e79bf0fdb2ac36494c51b573167c..8e8b41ba63eb49d60392fb2da8a458249731cf14 100644
--- a/substrate/frame/conviction-voting/src/tests.rs
+++ b/substrate/frame/conviction-voting/src/tests.rs
@@ -154,6 +154,7 @@ impl Config for Test {
 	type WeightInfo = ();
 	type MaxTurnout = frame_support::traits::TotalIssuanceOf<Balances, Self::AccountId>;
 	type Polls = TestPolls;
+	type BlockNumberProvider = System;
 }
 
 pub fn new_test_ext() -> sp_io::TestExternalities {
diff --git a/substrate/primitives/runtime/src/traits/mod.rs b/substrate/primitives/runtime/src/traits/mod.rs
index 8f5b484e4e3f5b84401ec5c0567bbfc83a853bf3..46f17a0fcc6337a9973b13ca03604c9c115f441e 100644
--- a/substrate/primitives/runtime/src/traits/mod.rs
+++ b/substrate/primitives/runtime/src/traits/mod.rs
@@ -2351,7 +2351,8 @@ pub trait BlockNumberProvider {
 		+ Debug
 		+ MaxEncodedLen
 		+ Copy
-		+ EncodeLike;
+		+ EncodeLike
+		+ Default;
 
 	/// Returns the current block number.
 	///