diff --git a/src/policy/semantic.rs b/src/policy/semantic.rs
index 740c493a7..6f18300a0 100644
--- a/src/policy/semantic.rs
+++ b/src/policy/semantic.rs
@@ -499,6 +499,34 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
         ret
     }
 
+    /// Helper function for recursion in `absolute timelocks`
+    fn real_absolute_timelocks(&self) -> Vec<u32> {
+        match *self {
+            Policy::Unsatisfiable
+            | Policy::Trivial
+            | Policy::KeyHash(..)
+            | Policy::Sha256(..)
+            | Policy::Hash256(..)
+            | Policy::Ripemd160(..)
+            | Policy::Hash160(..) => vec![],
+            Policy::Older(..) => vec![],
+            Policy::After(t) => vec![t],
+            Policy::Threshold(_, ref subs) => subs.iter().fold(vec![], |mut acc, x| {
+                acc.extend(x.real_absolute_timelocks());
+                acc
+            }),
+        }
+    }
+
+    /// Returns a list of all absolute timelocks, not including 0,
+    /// which appear in the policy
+    pub fn absolute_timelocks(&self) -> Vec<u32> {
+        let mut ret = self.real_absolute_timelocks();
+        ret.sort();
+        ret.dedup();
+        ret
+    }
+
     /// Filter a policy by eliminating relative timelock constraints
     /// that are not satisfied at the given age.
     pub fn at_age(mut self, time: u32) -> Policy<Pk> {
@@ -518,6 +546,25 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
         self.normalized()
     }
 
+    /// Filter a policy by eliminating absolute timelock constraints
+    /// that are not satisfied at the given age.
+    pub fn at_height(mut self, time: u32) -> Policy<Pk> {
+        self = match self {
+            Policy::After(t) => {
+                if t > time {
+                    Policy::Unsatisfiable
+                } else {
+                    Policy::After(t)
+                }
+            }
+            Policy::Threshold(k, subs) => {
+                Policy::Threshold(k, subs.into_iter().map(|sub| sub.at_height(time)).collect())
+            }
+            x => x,
+        };
+        self.normalized()
+    }
+
     /// Count the number of public keys and keyhashes referenced in a policy.
     /// Duplicate keys will be double-counted.
     pub fn n_keys(&self) -> usize {
@@ -604,6 +651,7 @@ mod tests {
         let policy = StringPolicy::from_str("pkh()").unwrap();
         assert_eq!(policy, Policy::KeyHash("".to_owned()));
         assert_eq!(policy.relative_timelocks(), vec![]);
+        assert_eq!(policy.absolute_timelocks(), vec![]);
         assert_eq!(policy.clone().at_age(0), policy.clone());
         assert_eq!(policy.clone().at_age(10000), policy.clone());
         assert_eq!(policy.n_keys(), 1);
@@ -611,6 +659,7 @@ mod tests {
 
         let policy = StringPolicy::from_str("older(1000)").unwrap();
         assert_eq!(policy, Policy::Older(1000));
+        assert_eq!(policy.absolute_timelocks(), vec![]);
         assert_eq!(policy.relative_timelocks(), vec![1000]);
         assert_eq!(policy.clone().at_age(0), Policy::Unsatisfiable);
         assert_eq!(policy.clone().at_age(999), Policy::Unsatisfiable);
@@ -628,6 +677,7 @@ mod tests {
             )
         );
         assert_eq!(policy.relative_timelocks(), vec![1000]);
+        assert_eq!(policy.absolute_timelocks(), vec![]);
         assert_eq!(policy.clone().at_age(0), Policy::KeyHash("".to_owned()));
         assert_eq!(policy.clone().at_age(999), Policy::KeyHash("".to_owned()));
         assert_eq!(policy.clone().at_age(1000), policy.clone().normalized());
@@ -658,6 +708,17 @@ mod tests {
             policy.relative_timelocks(),
             vec![1000, 2000, 10000] //sorted and dedup'd
         );
+
+        let policy = StringPolicy::from_str("after(1000)").unwrap();
+        assert_eq!(policy, Policy::After(1000));
+        assert_eq!(policy.absolute_timelocks(), vec![1000]);
+        assert_eq!(policy.relative_timelocks(), vec![]);
+        assert_eq!(policy.clone().at_height(0), Policy::Unsatisfiable);
+        assert_eq!(policy.clone().at_height(999), Policy::Unsatisfiable);
+        assert_eq!(policy.clone().at_height(1000), policy.clone());
+        assert_eq!(policy.clone().at_height(10000), policy.clone());
+        assert_eq!(policy.n_keys(), 0);
+        assert_eq!(policy.minimum_n_keys(), 0);
     }
 
     #[test]