diff --git a/addressfield.module b/addressfield.module
index db7e023..f773da0 100644
--- a/addressfield.module
+++ b/addressfield.module
@@ -133,12 +133,14 @@ function addressfield_format_plugins_options() {
  *   - instance: the field instance array.
  *   - langcode: the langcode of the language the field is being rendered in.
  *   - delta: the delta value of the given address.
+ * @param $available_countries
+ *   A list of countries to restrict the format to.
  *
  * @return
  *   A renderable array suitable for use as part of a form (if 'mode' is 'form')
  *   or for formatted address output when passed to drupal_render().
  */
-function addressfield_generate($address, array $handlers, array $context = array()) {
+function addressfield_generate($address, array $handlers, array $context = array(), array $available_countries = array()) {
   // If no mode is given in the context array, default it to 'render'.
   if (empty($context['mode'])) {
     $context['mode'] = 'render';
@@ -149,6 +151,7 @@ function addressfield_generate($address, array $handlers, array $context = array
   // Add the handlers, ordered by weight.
   $plugins = addressfield_format_plugins();
   $format['#handlers'] = array_intersect(array_keys($plugins), $handlers);
+  $format['#available_countries'] = $available_countries;
 
   foreach ($format['#handlers'] as $handler) {
     if ($callback = ctools_plugin_load_function('addressfield', 'format', $handler, 'format callback')) {
@@ -162,7 +165,6 @@ function addressfield_generate($address, array $handlers, array $context = array
   // Post-process the format stub, depending on the rendering mode.
   if ($context['mode'] == 'form') {
     $format['#addressfield'] = TRUE;
-    $format['#process'][] = 'addressfield_process_format_form';
   }
   elseif ($context['mode'] == 'render') {
     $format['#pre_render'][] = 'addressfield_render_address';
@@ -323,10 +325,76 @@ function addressfield_element_info() {
     '#attributes' => array(),
     '#tag' => 'div',
   );
+
+  $types['addressfield'] = array(
+    '#process' => array('addressfield_element_process'),
+    '#context' => array('mode' => 'form'),
+    '#handlers' => array('address' => 'address'),
+    '#available_countries' => array_keys(_addressfield_country_options_list()),
+    '#inline' => FALSE,
+  );
+
   return $types;
 }
 
 /**
+ * Addressfield process function.
+ */
+function addressfield_element_process($element, &$form_state, $form) {
+  $address = array();
+  // If the form has been rebuilt via AJAX, use the form state values.
+  // $form_state['values'] is empty because of #limit_validation_errors, so
+  // $form_state['input'] needs to be used instead.
+  $parents = $element['#parents'];
+  $input_address = drupal_array_get_nested_value($form_state['input'], $parents);
+  if (!empty($input_address)) {
+    $address = $input_address;
+  }
+  elseif (!empty($element['#default_value'])) {
+    // Else use the saved value for the field.
+    $address = $element['#default_value'];
+  }
+
+  // Determine the list of available countries, and if the currently selected
+  // country is not in it, unset it so it can be reset to the default country.
+  if (!empty($address['country']) && !in_array($address['country'], $element['#available_countries'])) {
+    unset($address['country']);
+  }
+
+  // Merge in default values. These only take effect if not already present from
+  // the settings in $element['#default_value'].
+  $default_country = isset($address['country']) ? $address['country'] : 'site_default';
+  $element['address'] = array();
+  $address += addressfield_default_values($element['#available_countries'], $default_country, $element['#context']);
+
+  // Generate the address form.
+  $element['address'] = addressfield_generate($address, $element['#handlers'], $element['#context'], $element['#available_countries']);
+  $element['address'] = addressfield_process_format_form($element['address'], $form_state, $form);
+
+  $element['address']['#type'] = (isset($element['#inline']) && $element['#inline'] == TRUE ? 'container' : 'fieldset');
+  if (isset($element['#title'])) {
+    $element['address']['#title'] = $element['#title'];
+  }
+
+  // Set the element to required based on the passed in required flag.
+  if (isset($element['#context']['instance']['required'])) {
+    $element['address']['country']['#required'] = $element['#context']['instance']['required'];
+  }
+  else if (isset($element['#required'])) {
+    $element['address']['country']['#required'] = $element['#required'];
+  }
+  
+  // Set the #parents of the children of this element so they appear at the same
+  // level as the parent.
+  foreach (element_children($element['address']) as $key) {
+    $element['address'][$key]['#parents'] = $element['#parents'];
+    $element['address'][$key]['#parents'][] = $key;
+  }
+
+  return $element;
+}
+
+/**
  * Form API process function: set the #parents of the children of this element so they appear at the same level as the parent.
  */
 function addressfield_widget_process($element) {
@@ -371,19 +439,17 @@ function addressfield_field_info() {
  * @return
  *   An array of default values.
  */
-function addressfield_default_values($field, $instance, array $address = array()) {
-  $available_countries = _addressfield_country_options_list($field, $instance);
-  $default_country = $instance['widget']['settings']['default_country'];
+function addressfield_default_values($available_countries, $default_country, $context) {
   // Resolve the special site_default option.
   if ($default_country == 'site_default') {
     $default_country = variable_get('site_default_country', '');
   }
   // Fallback to the first country in the list if the default country is not
   // available, or is empty even though the field is required.
-  $not_available = $default_country && !isset($available_countries[$default_country]);
+  $not_available = $default_country && !in_array($default_country, $available_countries);
   $empty_but_required = empty($default_country) && !empty($instance['required']);
   if ($not_available || $empty_but_required) {
-    $default_country = key($available_countries);
+    $default_country = reset($available_countries);
   }
 
   $default_values = array(
@@ -404,14 +470,34 @@ function addressfield_default_values($field, $instance, array $address = array()
   );
 
   // Allow other modules to alter the default values.
+  drupal_alter('addressfield_default_values', $default_values, $context);
+  return $default_values;
+}
+
+/**
+ * Returns an array of default values for the addressfield form elements.
+ *
+ * @param $field
+ *   The field array.
+ * @param $instance
+ *   The instance array.
+ * @param $address
+ *   The current address values, if known. Allows for per-country defaults.
+ *
+ * @return
+ *   An array of default values.
+ */
+function addressfield_default_values_for_field($field, $instance, array $address = array()) {
+  $available_countries = _addressfield_field_country_list($field, $instance);
+  $default_country = $instance['widget']['settings']['default_country'];
+
   $context = array(
     'field' => $field,
     'instance' => $instance,
     'address' => $address,
   );
-  drupal_alter('addressfield_default_values', $default_values, $context);
 
-  return $default_values;
+  return addressfield_default_values($available_countries, $default_country, $context);
 }
 
 /**
@@ -530,29 +616,14 @@ function addressfield_field_widget_form(&$form, &$form_state, $field, $instance,
   $settings = $instance['widget']['settings'];
 
   $address = array();
-  // If the form has been rebuilt via AJAX, use the form state values.
-  // $form_state['values'] is empty because of #limit_validation_errors, so
-  // $form_state['input'] needs to be used instead.
-  $parents = array_merge($element['#field_parents'], array($element['#field_name'], $langcode, $delta));
-  $input_address = drupal_array_get_nested_value($form_state['input'], $parents);
-  if (!empty($input_address)) {
-    $address = $input_address;
-  }
-  elseif (!empty($items[$delta]['country'])) {
+  if (!empty($items[$delta]['country'])) {
     // Else use the saved value for the field.
     $address = $items[$delta];
   }
-
-  // Determine the list of available countries, and if the currently selected
-  // country is not in it, unset it so it can be reset to the default country.
-  $countries = _addressfield_country_options_list($field, $instance);
-  if (!empty($address['country']) && !isset($countries[$address['country']])) {
-    unset($address['country']);
+  else {
+    $address['country'] = $instance['widget']['settings']['default_country'];
   }
 
-  // Merge in default values.
-  $address += addressfield_default_values($field, $instance, $address);
-
   // Add the form elements for the standard widget, which includes a country
   // select list at the top that reloads the available address elements when the
   // country is changed.
@@ -562,28 +633,23 @@ function addressfield_field_widget_form(&$form, &$form_state, $field, $instance,
     // in that context, and it is overridable if necessary.
     $element['#type'] = 'fieldset';
 
-    if (!empty($instance['description'])) {
-      // Checkout panes convert the fieldset into a container, causing
-      // #description to not be rendered. Hence, a real element is added and
-      // the old #description is removed.
-      $element['#description'] = '';
-      $element['element_description'] = array(
-        '#markup' =>  $instance['description'],
-        '#prefix' => '<div class="fieldset-description">',
-        '#suffix' => '</div>',
-        '#weight' => -999,
-      );
-    }
-
-    // Generate the address form.
-    $context = array(
-      'mode' => 'form',
-      'field' => $field,
-      'instance' => $instance,
-      'langcode' => $langcode,
-      'delta' => $delta,
+    $element['address'] = array(
+      '#type' => 'addressfield',
+      '#description' => $element['#description'],
+      '#default_value' => $address,
+      '#handlers' => $settings['format_handlers'],
+      '#available_countries' => _addressfield_field_country_list($field, $instance),
+      '#context' => array(
+        'mode' => 'form',
+        'field' => $field,
+        'instance' => $instance,
+        'address' => $address,
+        'langcode' => $langcode,
+        'delta' => $delta,
+      ),
+      // Ensure the submitted value doesn't have the ['address'] index.
+      '#parents' => array_merge($element['#field_parents'], array($element['#field_name'], $langcode, $delta)),
     );
-    $element += addressfield_generate($address, $settings['format_handlers'], $context);
 
     // Remove any already saved default value.
     // See addressfield_form_field_ui_field_edit_form_alter() for the reasoning.
@@ -799,7 +865,7 @@ function addressfield_property_info_callback(&$info, $entity_type, $field, $inst
  * @see addressfield_property_info_callback()
  */
 function addressfield_auto_creation($property_name, $context) {
-  return addressfield_default_values($context['field'], $context['instance']);
+  return addressfield_default_values_for_field($context['field'], $context['instance']);
 }
 
 /**
@@ -866,7 +932,7 @@ function addressfield_data_property_info($name = NULL) {
 /**
  * Returns the country list in a format suitable for use as an options list.
  */
-function _addressfield_country_options_list($field = NULL, $instance = NULL) {
+function _addressfield_country_options_list($limit_countries = array()) {
   if (module_exists('countries')) {
     $countries = countries_get_countries('name', array('enabled' => COUNTRIES_ENABLED));
   }
@@ -875,6 +941,16 @@ function _addressfield_country_options_list($field = NULL, $instance = NULL) {
     $countries = country_get_list();
   }
 
+  if (!empty($limit_countries)) {
+    $countries = array_intersect_key($countries, array_flip($limit_countries));
+  }
+
+  return $countries;
+}
+
+function _addressfield_field_country_list($field = NULL, $instance = NULL) {
+  $countries = array_keys(_addressfield_country_options_list());
+
   if (isset($field)) {
     // If the instance is not specified, loop against all the instances of the field.
     if (!isset($instance)) {
@@ -891,11 +967,10 @@ function _addressfield_country_options_list($field = NULL, $instance = NULL) {
 
     foreach ($instances as $instance) {
       if (!empty($instance['widget']['settings']['available_countries'])) {
-        $countries = array_intersect_key($countries, $instance['widget']['settings']['available_countries']);
+        $countries = array_intersect($countries, $instance['widget']['settings']['available_countries']);
         break;
       }
     }
   }
-
   return $countries;
 }
diff --git a/plugins/format/address.inc b/plugins/format/address.inc
index 0523ffe..983f384 100644
--- a/plugins/format/address.inc
+++ b/plugins/format/address.inc
@@ -271,8 +271,8 @@ function addressfield_format_address_generate(&$format, $address, $context = arr
     // Move the country selector to the top of the form.
     $format['country']['#weight'] = -500;
     // Limit it to the countries supported by the widget.
-    if (isset($context['field'])) {
-      $format['country']['#options'] = _addressfield_country_options_list($context['field'], $context['instance']);
+    if (isset($format['#available_countries'])) {
+      $format['country']['#options'] = _addressfield_country_options_list($format['#available_countries']);
     }
 
     // The whole field is considered empty if the country column is empty.
