diff --git a/polkadot/Cargo.lock b/polkadot/Cargo.lock
index 8583a3b1db514a6b65ba5c06bbac46d0e71dcbc7..9f8d5c94f08cdb268dedf467da3f42b0268ada91 100644
--- a/polkadot/Cargo.lock
+++ b/polkadot/Cargo.lock
@@ -4716,6 +4716,7 @@ dependencies = [
  "sp-consensus-babe",
  "sp-core",
  "sp-inherents",
+ "sp-io",
  "sp-keyring",
  "sp-offchain",
  "sp-runtime",
diff --git a/polkadot/runtime/polkadot/Cargo.toml b/polkadot/runtime/polkadot/Cargo.toml
index bad45c6aa127408583448eaed3faa221968695e9..7f1763ff298b1b9c3ded3063b31e8d2463ec8288 100644
--- a/polkadot/runtime/polkadot/Cargo.toml
+++ b/polkadot/runtime/polkadot/Cargo.toml
@@ -20,7 +20,8 @@ babe-primitives = { package = "sp-consensus-babe", git = "https://github.com/par
 sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 inherents = { package = "sp-inherents", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 offchain-primitives = { package = "sp-offchain", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
-sp-std = { package = "sp-std", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
+sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
+sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 sp-staking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
 sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
diff --git a/polkadot/runtime/polkadot/src/lib.rs b/polkadot/runtime/polkadot/src/lib.rs
index 258a7b4781b4ce8abc50223b8921464372265fc3..610a37f07ac3a43c41a6cca10c54210e422ce4c9 100644
--- a/polkadot/runtime/polkadot/src/lib.rs
+++ b/polkadot/runtime/polkadot/src/lib.rs
@@ -79,6 +79,7 @@ pub use parachains::Call as ParachainsCall;
 
 /// Constant values used within the runtime.
 pub mod constants;
+pub mod poll;
 use constants::{time::*, currency::*, fee::*};
 use frame_support::traits::InstanceFilter;
 
@@ -114,12 +115,7 @@ pub struct BaseFilter;
 impl Filter<Call> for BaseFilter {
 	fn filter(call: &Call) -> bool {
 		match call {
-			Call::Parachains(parachains::Call::set_heads(..))
-				| Call::Democracy(democracy::Call::vote(..))
-				| Call::Democracy(democracy::Call::remove_vote(..))
-				| Call::Democracy(democracy::Call::delegate(..))
-				| Call::Democracy(democracy::Call::undelegate(..))
-				=> true,
+			Call::Parachains(parachains::Call::set_heads(..)) => true,
 
 			// Governance stuff
 			Call::Democracy(_) | Call::Council(_) | Call::TechnicalCommittee(_) |
@@ -138,7 +134,7 @@ impl Filter<Call> for BaseFilter {
 			Call::Session(_) | Call::FinalityTracker(_) | Call::Grandpa(_) | Call::ImOnline(_) |
 			Call::AuthorityDiscovery(_) |
 			Call::Utility(_) | Call::Claims(_) | Call::Vesting(_) | Call::Sudo(_) |
-			Call::Identity(_) | Call::Proxy(_) | Call::Multisig(_) =>
+			Call::Identity(_) | Call::Proxy(_) | Call::Multisig(_) | Call::Poll(_)  =>
 				true,
 		}
 	}
@@ -893,6 +889,7 @@ impl InstanceFilter<Call> for ProxyType {
 			ProxyType::Governance => matches!(c,
 				Call::Democracy(..) | Call::Council(..) | Call::TechnicalCommittee(..)
 					| Call::ElectionsPhragmen(..) | Call::Treasury(..) | Call::Utility(..)
+					| Call::Poll(..)
 			),
 			ProxyType::Staking => matches!(c,
 				Call::Staking(..) | Call::Utility(utility::Call::batch(..)) | Call::Utility(..)
@@ -941,6 +938,16 @@ impl frame_support::traits::OnRuntimeUpgrade for CustomOnRuntimeUpgrade {
 	}
 }
 
+parameter_types! {
+	pub const PollEnd: BlockNumber = 100_000;
+}
+
+impl poll::Trait for Runtime {
+	type Event = Event;
+	type Currency = Balances;
+	type End = PollEnd;
+}
+
 construct_runtime! {
 	pub enum Runtime where
 		Block = Block,
@@ -1006,6 +1013,9 @@ construct_runtime! {
 
 		// Multisig dispatch. Late addition.
 		Multisig: multisig::{Module, Call, Storage, Event<T>},
+
+		// Poll module.
+		Poll: poll::{Module, Call, Storage, Event<T>},
 	}
 }
 
diff --git a/polkadot/runtime/polkadot/src/poll.rs b/polkadot/runtime/polkadot/src/poll.rs
new file mode 100644
index 0000000000000000000000000000000000000000..c2cd5518178b76d7670cd6f1c85f21dff90bcae2
--- /dev/null
+++ b/polkadot/runtime/polkadot/src/poll.rs
@@ -0,0 +1,233 @@
+// Copyright 2020 Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! # Simple polling module
+//!
+//! Note: This implementation assumes that all accounts are locked, and thus that no account balance
+//! may ever reduce.
+
+use frame_support::{
+	decl_module, decl_storage, decl_event, decl_error, ensure, traits::{Currency, Get},
+};
+use system::{self as frame_system, ensure_signed};
+use sp_runtime::traits::Saturating;
+
+pub type BalanceOf<T> =
+	<<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
+
+pub trait Trait: system::Trait {
+	/// The overarching event type.
+	type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
+
+	/// The currency type used.
+	type Currency: Currency<Self::AccountId>;
+
+	/// The block number only before which voting is possible.
+	type End: Get<Self::BlockNumber>;
+}
+
+/// The options someone has approved.
+pub type Approvals = [bool; 4];
+
+decl_storage! {
+	trait Store for Module<T: Trait> as Poll {
+		/// Votes, so far.
+		pub VoteOf: map hasher(twox_64_concat) T::AccountId => (Approvals, BalanceOf<T>);
+
+		/// The total balances voting for each option.
+		pub Totals: [BalanceOf<T>; 4];
+	}
+}
+
+decl_event! {
+	pub enum Event<T> where
+		<T as system::Trait>::AccountId,
+		Balance = BalanceOf<T>,
+	{
+		Voted(AccountId, Balance, Approvals),
+	}
+}
+
+decl_error! {
+	pub enum Error for Module<T: Trait> {
+		/// Vote attempted after the end of voting.
+		TooLate,
+	}
+}
+
+decl_module! {
+	pub struct Module<T: Trait> for enum Call where origin: T::Origin {
+		type Error = Error<T>;
+
+		fn deposit_event() = default;
+
+		/// The End config param.
+		const End: T::BlockNumber = T::End::get();
+
+		/// Cast a vote on the poll.
+		#[weight = 100_000_000]
+		fn vote(origin, approvals: Approvals) {
+			let who = ensure_signed(origin)?;
+			ensure!(system::Module::<T>::block_number() < T::End::get(), Error::<T>::TooLate);
+			let balance = T::Currency::total_balance(&who);
+			Totals::<T>::mutate(|ref mut totals| {
+				VoteOf::<T>::mutate(&who, |(ref mut who_approvals, ref mut who_balance)| {
+					for i in 0..approvals.len() {
+						if who_approvals[i] {
+							totals[i] = totals[i].saturating_sub(*who_balance);
+						}
+						if approvals[i] {
+							totals[i] = totals[i].saturating_add(balance);
+						}
+					}
+					*who_approvals = approvals;
+					*who_balance = balance;
+				});
+			});
+			Self::deposit_event(RawEvent::Voted(who, balance, approvals));
+		}
+	}
+}
+
+#[cfg(test)]
+mod tests {
+	use super::*;
+
+	use frame_support::{assert_ok, assert_noop, impl_outer_origin, parameter_types, weights::Weight};
+	use sp_core::H256;
+	use sp_runtime::{Perbill, testing::Header, traits::{BlakeTwo256, IdentityLookup}};
+
+	impl_outer_origin! {
+		pub enum Origin for Test where system = frame_system {}
+	}
+
+	// For testing the pallet, we construct most of a mock runtime. This means
+	// first constructing a configuration type (`Test`) which `impl`s each of the
+	// configuration traits of pallets we want to use.
+	#[derive(Clone, Eq, PartialEq)]
+	pub struct Test;
+	parameter_types! {
+		pub const BlockHashCount: u64 = 250;
+		pub const MaximumBlockWeight: Weight = 1024;
+		pub const MaximumBlockLength: u32 = 2 * 1024;
+		pub const AvailableBlockRatio: Perbill = Perbill::one();
+	}
+	impl frame_system::Trait for Test {
+		type BaseCallFilter = ();
+		type Origin = Origin;
+		type Index = u64;
+		type BlockNumber = u64;
+		type Hash = H256;
+		type Call = ();
+		type Hashing = BlakeTwo256;
+		type AccountId = u64;
+		type Lookup = IdentityLookup<Self::AccountId>;
+		type Header = Header;
+		type Event = ();
+		type BlockHashCount = BlockHashCount;
+		type MaximumBlockWeight = MaximumBlockWeight;
+		type DbWeight = ();
+		type BlockExecutionWeight = ();
+		type ExtrinsicBaseWeight = ();
+		type MaximumExtrinsicWeight = MaximumBlockWeight;
+		type MaximumBlockLength = MaximumBlockLength;
+		type AvailableBlockRatio = AvailableBlockRatio;
+		type Version = ();
+		type ModuleToIndex = ();
+		type AccountData = balances::AccountData<u64>;
+		type OnNewAccount = ();
+		type OnKilledAccount = ();
+		type SystemWeightInfo = ();
+	}
+	parameter_types! {
+		pub const ExistentialDeposit: u64 = 1;
+	}
+	impl balances::Trait for Test {
+		type Balance = u64;
+		type Event = ();
+		type DustRemoval = ();
+		type ExistentialDeposit = ExistentialDeposit;
+		type AccountStore = System;
+		type WeightInfo = ();
+	}
+	parameter_types! {
+		pub const End: u64 = 1;
+	}
+	impl Trait for Test {
+		type Event = ();
+		type Currency = Balances;
+		type End = End;
+	}
+	type System = system::Module<Test>;
+	type Balances = balances::Module<Test>;
+	type Poll = Module<Test>;
+
+	// This function basically just builds a genesis storage key/value store according to
+	// our desired mockup.
+	pub fn new_test_ext() -> sp_io::TestExternalities {
+		let mut t = system::GenesisConfig::default().build_storage::<Test>().unwrap();
+		// We use default for brevity, but you can configure as desired if needed.
+		balances::GenesisConfig::<Test> {
+			balances: vec![
+				(1, 10),
+				(2, 20),
+				(3, 30),
+				(4, 40),
+			],
+		}.assimilate_storage(&mut t).unwrap();
+		t.into()
+	}
+
+	#[test]
+	fn basic_setup_works() {
+		new_test_ext().execute_with(|| {
+			assert_eq!(System::block_number(), 0);
+		});
+	}
+
+	#[test]
+	fn totaling_works() {
+		new_test_ext().execute_with(|| {
+			assert_ok!(Poll::vote(Origin::signed(1), [true, true, false, false]));
+			assert_ok!(Poll::vote(Origin::signed(2), [false, true, true, false]));
+			assert_ok!(Poll::vote(Origin::signed(3), [false, false, true, true]));
+			assert_ok!(Poll::vote(Origin::signed(4), [true, false, false, true]));
+			assert_eq!(Totals::<Test>::get(), [50, 30, 50, 70]);
+		});
+	}
+
+	#[test]
+	fn revoting_works() {
+		new_test_ext().execute_with(|| {
+			assert_ok!(Poll::vote(Origin::signed(1), [true, false, false, false]));
+			assert_eq!(Totals::<Test>::get(), [10, 0, 0, 0]);
+			assert_ok!(Poll::vote(Origin::signed(1), [false, true, false, false]));
+			assert_eq!(Totals::<Test>::get(), [0, 10, 0, 0]);
+			assert_ok!(Poll::vote(Origin::signed(1), [false, false, true, true]));
+			assert_eq!(Totals::<Test>::get(), [0, 0, 10, 10]);
+		});
+	}
+
+	#[test]
+	fn vote_end_works() {
+		new_test_ext().execute_with(|| {
+			assert_ok!(Poll::vote(Origin::signed(1), [true, false, false, false]));
+			assert_eq!(Totals::<Test>::get(), [10, 0, 0, 0]);
+			system::Module::<Test>::set_block_number(1);
+			assert_noop!(Poll::vote(Origin::signed(1), [false, true, false, false]), Error::<Test>::TooLate);
+		});
+	}
+}